﻿using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using Microsoft.SharePoint;
using Microsoft.SharePoint.Linq;

namespace ZhukBlogLinqExamples.Model.Meta
{
    /// <summary>
    /// Мета данные списка
    /// </summary>
    public class EntityListMetaData
    {
        public string ServerRelativeUrl { get; set; }
        public EntityListBaseType BaseType { get; set; }
        public List<EntityListContentTypeInfo> ContentTypes { get; set; }
        public string Description { get; set; }
        public bool EnableAttachments { get; set; }
        public List<EntityListFieldInfo> Fields { get; set; }
        public bool Hidden { get; set; }
        public Guid Id { get; set; }
        public bool IsUserInfoList { get; set; }
        public bool IsVirtual { get; set; }
        public SPList List { get; set; }
        public string Name { get; set; }

        private EntityListMetaData()
        { }

        /// <summary>
        /// Получение мета данных списка
        /// </summary>
        /// <param name="entityList">Список</param>
        public static EntityListMetaData GetMetaData<T>(EntityList<T> entityList) where T : ZhukDataItem
        {
            var res = new EntityListMetaData();
            // Получаем имена свойств для маппинга в дальнейшем
            var propNames = typeof(EntityListMetaData).GetProperties().Select(p => p.Name);
            var entityType = typeof(EntityList<T>);
            // Получаем приватное поле field
            var listField = entityType.GetField("list",
                BindingFlags.NonPublic | BindingFlags.Instance);
            // Получаем значение поля field
            var listValue = listField.GetValue(entityList);
            // Получаем тип этого поля (Microsoft.SharePoint.Linq.Provider.SPServerDataList)
            var listType = listValue.GetType();
            // Получаем свойства типа SPServerDataList
            var listProperties = listType.GetProperties();
            foreach (var listProperty in listProperties)
            {
                // Если поле отсутствует в нашем классе, то пропускаем его
                if (!propNames.Contains(listProperty.Name)) continue;
                // Получаем значение поля
                var listPropertyValue = listProperty.GetValue(listValue, null);
                // Свойство ContentTypes обрабатываем в "ручном" режиме
                if (listProperty.Name == "ContentTypes")
                {
                    res.ContentTypes = new List<EntityListContentTypeInfo>();
                    var ctypes = listPropertyValue as IEnumerable;
                    if (ctypes != null)
                    {
                        // Перебираем типы содержимого
                        foreach (var ctype in ctypes)
                        {
                            var ct = new EntityListContentTypeInfo
                            {
                                Id = ctype.GetPropertyValue<string>("Id"),
                                Name = ctype.GetPropertyValue<string>("Name"),
                                Description = ctype.GetPropertyValue<string>("Description"),
                                Hidden = ctype.GetPropertyValue<bool>("Hidden")
                            };
                            res.ContentTypes.Add(ct);
                        }
                    }
                }
                // Свойство Fields обрабатываем в "ручном" режиме
                else if (listProperty.Name == "Fields")
                {
                    res.Fields = new List<EntityListFieldInfo>();
                    var fields = listPropertyValue as IEnumerable;
                    if (fields != null)
                    {
                        foreach (var field in fields)
                        {
                            var ef = new EntityListFieldInfo
                            {
                                Id = field.GetPropertyValue<Guid>("Id"),
                                Title = field.GetPropertyValue<string>("Title"),
                                InternalName = field.GetPropertyValue<string>("InternalName"),
                                FieldType = field.GetPropertyValue<EntityListFieldType>("FieldType"),
                                //AllowMultipleValues = field.GetPropertyValue<bool>("AllowMultipleValues"),
                                //Choices = field.GetPropertyValue<IEnumerable>("Choices"),
                                //FillInChoice = field.GetPropertyValue<bool>("FillInChoice"),
                                Hidden = field.GetPropertyValue<bool>("Hidden"),
                                IsCalculated = field.GetPropertyValue<bool>("IsCalculated"),
                                ReadOnlyField = field.GetPropertyValue<bool>("ReadOnlyField"),
                                Required = field.GetPropertyValue<bool>("Required"),
                                Description = field.GetPropertyValue<string>("Description"),
                                //LookupDisplayColumn = field.GetPropertyValue<string>("LookupDisplayColumn"),
                                //LookupList = field.GetPropertyValue<string>("LookupList"),
                                //PrimaryFieldId = field.GetPropertyValue<string>("PrimaryFieldId")
                            };
                            res.Fields.Add(ef);
                        }
                    }
                }
                else
                {
                    // Свойство текущего класса
                    var property = typeof(EntityListMetaData).GetProperty(listProperty.Name);
                    // Задаем полученное значение
                    property.SetValue(res, listPropertyValue, null);
                }
            }
            // возвращаем результат
            return res;
        }
    }
}
